package gbase

import (
	"fmt"
	"io"
	"net/http"
	"strings"
	"time"

	"github.com/cloudwego/hertz/pkg/common/hlog"
)

const (
	// 内容类型常量
	ContentTypeKey       = "Content-Type"
	ContentTypeJSON      = "application/json"
	ContentTypeForm      = "application/x-www-form-urlencoded"
	ContentTypeMultipart = "multipart/form-data"
	ContentTypeXML       = "application/xml"
	ContentTypeText      = "text/plain"

	// 默认超时时间（秒）
	DefaultTimeout = 60

	// HTTP方法
	MethodGet     = "GET"
	MethodPost    = "POST"
	MethodPut     = "PUT"
	MethodDelete  = "DELETE"
	MethodPatch   = "PATCH"
	MethodHead    = "HEAD"
	MethodOptions = "OPTIONS"
)

// 基于标准库的HTTP客户端
type HttpClient struct {
	Client *http.Client
	//transport   *http.Transport
	headers Map
	//cookies     []*http.Cookie
	//url         string
	//method      string
	//queryParams url.Values
	//formData    url.Values
	//multipart   *multipart.Writer
	//body        io.Reader
	//bodyBuf     *bytes.Buffer
	//contentType string
	//timeout     time.Duration
	//ctx         context.Context
	//retryCount  int
	//retryWait   time.Duration
	//mutex       sync.RWMutex
	debug bool
}

// SetDebug 实现Debuggable接口
func (c *HttpClient) SetDebug(debug bool) {
	c.debug = debug
}

func (c *HttpClient) Do(method, url string, params ...Map) *Resp {

	var (
		bodyStr string
		//body io.Reader
	)
	switch method {
	case MethodGet:
		if len(params) > 0 && params[0] != nil {
			url = fmt.Sprintf("%s?%s", url, params[0].ToUrlParamsStr())
		}
	case MethodPost:
		//这里要区分content-type
		if len(params) > 0 && params[0] != nil {
			if c.headers.GetString(ContentTypeKey) == ContentTypeJSON {
				bodyStr = params[0].ToSortString()
			} else if c.headers.GetString(ContentTypeKey) == ContentTypeXML {
				bodyStr = params[0].ToXmlStr()
			} else if c.headers.GetString(ContentTypeKey) == ContentTypeText {
				bodyStr = params[0].ToSortString()
			} else {
				bodyStr = params[0].ToUrlParamsStr()
			}
		}
	case MethodPut:
		//这里要区分content-type
		if len(params) > 0 && params[0] != nil {
			if c.headers.GetString(ContentTypeKey) == ContentTypeJSON {
				bodyStr = params[0].ToSortString()
			} else if c.headers.GetString(ContentTypeKey) == ContentTypeXML {
				bodyStr = params[0].ToXmlStr()
			} else if c.headers.GetString(ContentTypeKey) == ContentTypeText {
				bodyStr = params[0].ToSortString()
			} else {
				bodyStr = params[0].ToUrlParamsStr()
			}
		}
	case MethodDelete:
		if len(params) > 0 && params[0] != nil {
			url = fmt.Sprintf("%s?%s", url, params[0].ToUrlParamsStr())
		}
	default:
		return NewFailResp(100, "gbase.HttpClient库未实现该请求方法")
	}

	if c.debug {
		hlog.Debugf("HttpClient.Do[%s]%s", method, url)
		if bodyStr != "" {
			hlog.Debugf("参数:%s", bodyStr)

		}
		if !c.headers.IsEmpty() {
			hlog.Debugf("headers:%s", c.headers.ToString())
		}
		// if h.transport.Proxy != nil {
		// 	hlog.Debugf("使用代理")
		// }
	}
	req, err := http.NewRequest(strings.ToUpper(method), url, strings.NewReader(bodyStr))
	if err != nil {
		return NewFailResp(100, "请求失败")
	}

	// 添加请求头
	if c.headers != nil {
		for k, v := range c.headers {
			req.Header.Set(k, fmt.Sprintf("%v", v))
		}
	}

	if httpResp, err := c.Client.Do(req); err != nil {
		if c.debug {
			hlog.Debugf("[%s %s]请求失败，err:%s", method, url, err.Error())
		}
		return NewFailResp(100, "请求失败")
	} else {
		defer httpResp.Body.Close()
		respStr, err := io.ReadAll(httpResp.Body)
		if err != nil {
			if c.debug {
				hlog.Debugf("读取响应数据失败，err:%s", err.Error())
			}
			return NewFailResp(100, "请求失败")
		}
		if c.debug {
			hlog.Debugf("[%s %s]响应数据:%s", method, url, string(respStr))
		}
		return NewSuccessResp(200, string(respStr), "ok")
	}
}

// Get 发起GET请求
func (c *HttpClient) Get(url string, params ...Map) *Resp {
	return c.Do(MethodGet, url, params...)
	//if len(params) > 0 && params[0] != nil {
	//	url = fmt.Sprintf("%s?%s", url, params[0].ToUrlParamsStr())
	//}
	//
	//if c.debug {
	//	hlog.Debugf("请求URL: %s", url)
	//	hlog.Debugf("请求方法: %s", MethodGet)
	//	//hlog.Debugf("请求头: %v", req.Header)
	//	// if h.transport.Proxy != nil {
	//	// 	hlog.Debugf("使用代理")
	//	// }
	//}
	//req, err := http.NewRequest(MethodGet, url, nil)
	//if err != nil {
	//	return NewFailResp(100, "请求失败")
	//} else if httpResp, err := c.Client.Do(req); err != nil {
	//	return NewFailResp(100, "请求失败")
	//} else {
	//	defer httpResp.Body.Close()
	//	respStr, err := io.ReadAll(httpResp.Body)
	//	if err != nil {
	//		return NewFailResp(100, "请求失败")
	//	}
	//	return NewSuccessResp(200, string(respStr), "ok")
	//}
}

func (c *HttpClient) Post(url string, params ...Map) *Resp {
	return c.Do(MethodPost, url, params...)
}

func (c *HttpClient) Put(url string, params ...Map) *Resp {
	return c.Do(MethodPut, url, params...)
}

func (c *HttpClient) SetHeader(key, value string) *HttpClient {
	if c.headers == nil {
		c.headers = Map{}
	}
	c.headers[key] = value
	return c
}

func NewHttpClient(opts ...Option[*HttpClient]) (obj *HttpClient) {

	obj = &HttpClient{
		Client: &http.Client{
			Timeout: DefaultTimeout * time.Second,
		},
		headers: Map{},
	}
	for _, opt := range opts {
		opt(obj)
	}
	return
}
